#include "PaintWidget.h"

#include <QDebug>

PaintWidget::PaintWidget(QWidget *parent) : QWidget(parent)
{
    init();
}

PaintWidget::~PaintWidget()
{
    if(selectPropertyWidget)
        delete selectPropertyWidget;
    selectPropertyWidget = nullptr;

    if(whiteBoardFile)
        delete whiteBoardFile;
    whiteBoardFile = nullptr;
}

void PaintWidget::SaveData()
{
    QString curDt = APPPATH + "/" + PAINTFILE::DIRNAME + "/" + CURDT;
    whiteBoardFile->SavePaintData(&PaintData,BackgroundColor,grab().toImage(),curDt);
}

void PaintWidget::ClearPaint()
{
    PaintData.clear();
    PaintStep = 0;

    update();
}

void PaintWidget::RevocationSingleStep()
{
    unsigned int totalStep = static_cast<unsigned int>(PaintData.size());
    if(totalStep > 0)
    {
        PaintData.remove(totalStep-1);
        --PaintStep;
    }

    update();
}

void PaintWidget::ReadFileData(const QString &tag)
{
    QMap<QString,QPair<QString,QString>> ld = whiteBoardFile->FindQuote();
    if(!ld.isEmpty())
    {
        QString jsonFilePath = APPPATH + "/" + PAINTFILE::DIRNAME + "/" + ld.value(tag).second;
        QByteArray data = whiteBoardFile->ReadJsonData(jsonFilePath);
        ClearPaint();

        QJsonParseError parseJsonErr;
        QJsonDocument document = QJsonDocument::fromJson(data,&parseJsonErr);
        if(parseJsonErr.error == QJsonParseError::NoError)
        {
            QJsonObject MainJsonObject = document.object();

            if(MainJsonObject.contains("BackgroundColor"))
            {
                QJsonArray JsonArray_PaintBackgroundColor = MainJsonObject.value("BackgroundColor").toArray();
                int r = JsonArray_PaintBackgroundColor.at(0).toInt();
                int g = JsonArray_PaintBackgroundColor.at(1).toInt();
                int b = JsonArray_PaintBackgroundColor.at(2).toInt();
                QColor painterBck(r,g,b);

                setBackgroundColor(painterBck);
            }

            for(unsigned short index=0;index<65535;++index)
            {
                QString value = QString::number(index);
                if(MainJsonObject.contains(value))
                {
                    PW::PROPERTYDATA pd;
                    pd.IsSelect = false;

                    QJsonObject JsonObject_Number = MainJsonObject.value(value).toObject();

                    // ModelType
                    if(JsonObject_Number.contains("ModelType"))
                        pd.Mt = static_cast<PW::ModelType>(JsonObject_Number.value("ModelType").toInt());

                    // PLOYGONTYPE
                    if(JsonObject_Number.contains("PLYGNTYPE"))
                        pd.Pt = static_cast<PW::PLOYGONTYPE>(JsonObject_Number.value("PLYGNTYPE").toInt());

                    // IsShow
                    if(JsonObject_Number.contains("IsShow"))
                        pd.IsShow = JsonObject_Number.value("IsShow").toBool();

                    // Pen
                    if(JsonObject_Number.contains("Pen"))
                    {
                        QPen Pen;
                        QJsonObject JsonObject_Pen = JsonObject_Number.value("Pen").toObject();
                        if(JsonObject_Pen.contains("Color"))
                        {
                            QJsonArray JsonArray_Pen_Color = JsonObject_Pen.value("Color").toArray();
                            int r = JsonArray_Pen_Color[0].toInt();
                            int g = JsonArray_Pen_Color[1].toInt();
                            int b = JsonArray_Pen_Color[2].toInt();
                            Pen.setColor(QColor(r,g,b));
                        }
                        if(JsonObject_Pen.contains("Width"))
                            Pen.setWidth(JsonObject_Pen.value("Width").toInt());

                        pd.pen = Pen;
                    }

                    // BeginEndPoint
                    if(JsonObject_Number.contains("BeginEndPoint"))
                    {
                        QJsonArray JsonArray_BeginEndPoint = JsonObject_Number.value("BeginEndPoint").toArray();
                        QPoint BeginPoint(JsonArray_BeginEndPoint[0].toArray()[0].toInt(),JsonArray_BeginEndPoint[0].toArray()[1].toInt());
                        QPoint EndPoint(JsonArray_BeginEndPoint[1].toArray()[0].toInt(),JsonArray_BeginEndPoint[1].toArray()[1].toInt());
                        pd.BeginEndPoint = QPair<QPoint,QPoint>(BeginPoint,EndPoint);
                    }

                    // PaintData
                    if(JsonObject_Number.contains("PaintData"))
                    {
                        QJsonArray JsonArray_PaintData = JsonObject_Number.value("PaintData").toArray();
                        int PaintDataCnt = JsonArray_PaintData.size();
                        QList<QPoint> points;
                        for(int index=0;index<PaintDataCnt;++index)
                        {
                            QPoint point(JsonArray_PaintData[index].toArray()[0].toInt(),JsonArray_PaintData[index].toArray()[1].toInt());
                            points.append(point);
                        }
                        pd.PaintData = points;
                    }
                    PaintData[PaintStep] = pd;
                    ++PaintStep;
                }
                else
                    break;
            }
        }
        update();
    }
}

void PaintWidget::init()
{
    mt = PW::ModelType::FREELINE;
    pt = PW::PLOYGONTYPE::RECTANGLE;
    BackgroundColor = COLORS::COLOR_Black;

    pen.setColor(COLORS::COLOR_Black);
    pen.setWidth(SIZES::SizeRate * 1);

    MouseLeftIsPressed = false;
    PaintStep = 0;
    SelectCnt = -1;


    whiteBoardFile = nullptr;
    whiteBoardFile = new WhiteBoardFile(this);

    selectPropertyWidget = nullptr;
    selectPropertyWidget = new SelectPropertyWidget(this);
    connect(selectPropertyWidget,&SelectPropertyWidget::deleteBtnSlot,this,&PaintWidget::deletePloygon);
    selectPropertyWidget->hide();
}

void PaintWidget::setModelType(const PW::ModelType &Mt)
{
    mt = Mt;
}

void PaintWidget::setPloygonType(const PW::PLOYGONTYPE &Pt)
{
    pt = Pt;
}

void PaintWidget::setPen(const QPen &Pen)
{
    pen = Pen;
    pen.setCapStyle(Qt::MPenCapStyle);
}

void PaintWidget::setBackgroundColor(const QColor &bck)
{
    BackgroundColor = bck;
    setPalette(QPalette(BackgroundColor));
    emit changeBackgroundColor(bck);
    emit setNormalEraser();
    mt = PW::ModelType::ERASER;
    for(auto it=PaintData.begin();it!=PaintData.end();++it)
        if(it->Mt == PW::ModelType::ERASER)
            it.value().pen.setColor(BackgroundColor);
}

WhiteBoardFile *PaintWidget::GetFilePtr()
{
    return whiteBoardFile;
}

void PaintWidget::paintRectangle(QPainter *painter, PW::PROPERTYDATA *sp)
{
    QPair<QPoint,QPoint> BeginEndPoint = sp->BeginEndPoint;

    if(painter && sp->IsShow)
    {
        QPair<QPoint, QPoint> points = BeginEndPoint;
        painter->drawRect(QRect(points.first,points.second));

        QVector<QPoint> border;
        int startX = points.first.x();
        int startY = points.first.y();
        int endX   = points.second.x();
        int endY   = points.second.y();
        int offset = painter->pen().width() + 6;

        if(startX<endX && startY<endY)
        {
            int side1Len = endY - startY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(startX-offset,startY+cnt));
            int side2Len = endX - startX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(startX+cnt,endY+offset));
            int side3Len = endY - startY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(endX+offset,endY-cnt));
            int side4Len = endX - startX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(endX-cnt,startY-offset));
        }

        else if(startX>endX && startY<endY)
        {
            int side1Len = endY - startY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(endX-offset,startY+cnt));
            int side2Len = startX - endX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(endX+cnt,endY+offset));
            int side3Len = endY - startY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(startX+offset,endY-cnt));
            int side4Len = startX - endX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(startX-cnt,startY-offset));
        }
        else if(startX<endX && startY>endY)
        {
            int side1Len = startY - endY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(startX-offset,endY+cnt));

            int side2Len = endX - startX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(startX+cnt,startY+offset));

            int side3Len = startY - endY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(endX+offset,startY-cnt));

            int side4Len = endX - startX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(endX-cnt,endY-offset));
        }

        else if(startX>endX && startY>endY)
        {
            int side1Len = startY - endY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(endX-offset,endY+cnt));

            int side2Len = startX - endX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(endX+cnt,startY+offset));

            int side3Len = startY - endY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(startX+offset,startY-cnt));

            int side4Len = startX - endX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(startX-cnt,endY-offset));
        }

        if(sp->IsSelect)
        {
            painter->save();
            QPen pen(Qt::gray,2);
//            pen.setStyle(Qt::DotLine);
            painter->setPen(pen);
            painter->drawLines(border);
            painter->restore();

            selectPropertyWidget->setProperty(BeginEndPoint,ReceiveSelectCnt);
        }
    }
    painter = nullptr;
    sp = nullptr;
}


bool PaintWidget::IsSelectPolygon(const QPoint &mPoint,PW::PROPERTYDATA &polygon)
{
    bool flag = false;

    QPoint p1 = polygon.BeginEndPoint.first;
    QPoint p3 = polygon.BeginEndPoint.second;
    int testX = mPoint.x();
    int testY = mPoint.y();
    int p1X = p1.x();
    int p1Y = p1.y();
    int p2X = p3.x();
    int p2Y = p3.y();
    flag =  (
                (p1X < testX && testX < p2X && p1Y < testY && testY < p2Y)||        // 右下方向
                (p1X > testX && testX > p2X && p1Y > testY && testY > p2Y)||        // 左上方向
                (p1X > testX && testX > p2X && p1Y < testY && testY < p2Y)||        // 左下方向
                (p1X < testX && testX < p2X && p1Y > testY && testY > p2Y)          // 右上方向
            );

    return flag;
}

void PaintWidget::deletePloygon(const int &number)
{
    for(auto it=PaintData.begin();it!=PaintData.end();++it)
        if(it.key() == number)
            it.value().IsShow = false;
    update();
}


void PaintWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    if(!selectPropertyWidget->isHidden())
        selectPropertyWidget->hide();

    for(QMap<unsigned int,PW::PROPERTYDATA>::iterator it=PaintData.begin();it!=PaintData.end();++it)
    {
        PW::PROPERTYDATA pd = it.value();

        if(pd.Mt == PW::ModelType::FREELINE || pd.Mt == PW::ModelType::ERASER || pd.Mt == PW::ModelType::LUCENCY || pd.Mt == PW::ModelType::NITELINE)
        {
            painter.setPen(pd.pen);
            for(unsigned short index=0;index<pd.PaintData.size()-1;++index)
            {
                QPoint first = pd.PaintData[index];
                QPoint second = pd.PaintData[index+1];
                if (pd.Mt == PW::ModelType::LUCENCY) {
                    painter.setCompositionMode(QPainter::CompositionMode_Clear);
                    painter.drawLine(first.x(),first.y(),second.x(),second.y());
                    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
                    QPen p = QPen(QColor(255,255,255,1),12);
                    painter.setPen(p);
                    painter.drawLine(first.x(),first.y(),second.x(),second.y());
                }else if (pd.Mt == PW::ModelType::NITELINE) {
                    qDebug("121");
                    painter.setCompositionMode(QPainter::CompositionMode_Source);
                    painter.drawLine(first.x(),first.y(),second.x(),second.y());
                }else {
                    painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
                    painter.drawLine(first.x(),first.y(),second.x(),second.y());
                }
            }
        }
    }

    for(QMap<unsigned int,PW::PROPERTYDATA>::iterator it=PaintData.begin();it!=PaintData.end();++it)
    {
        PW::PROPERTYDATA pd = it.value();
        if(pd.Mt == PW::ModelType::PLOYGON)
        {
            painter.setPen(pd.pen);
            if(pd.Pt == PW::PLOYGONTYPE::RECTANGLE)
                paintRectangle(&painter,&pd);
            else if(pd.Pt == PW::PLOYGONTYPE::ELLIPOSE)
                paintEllipose(&painter,&pd);
        }
    }

//    for(QMap<unsigned int,PW::PROPERTYDATA>::iterator it=PaintData.begin();it!=PaintData.end();++it)
//    {
//        PW::PROPERTYDATA pd = it.value();
//        painter.setPen(pd.pen);
//        if(pd.Mt == PW::ModelType::FREELINE || pd.Mt == PW::ModelType::ERASER)
//        {
//            for(unsigned short index=0;index<pd.PaintData.size()-1;++index)
//            {
//                QPoint first = pd.PaintData[index];
//                QPoint second = pd.PaintData[index+1];
//                painter.drawLine(first.x(),first.y(),second.x(),second.y());
//            }
//        }
//        else if(pd.Mt == PW::ModelType::PLOYGON)
//        {
//            if(pd.Pt == PW::PLOYGONTYPE::RECTANGLE)
//                paintRectangle(&painter,&pd);
//            else if(pd.Pt == PW::PLOYGONTYPE::ELLIPOSE)
//                paintEllipose(&painter,&pd);
//        }
//    }
}

void PaintWidget::mousePressEvent(QMouseEvent *pEvent)
{
    emit LeftButtonPressed();
    if(pEvent->button() == Qt::LeftButton)
    {
        MouseLeftIsPressed = true;
        QPoint curPoint = pEvent->pos();
        MouseLeftPressedPoint = curPoint;
        TmpPoints.append(curPoint);
        SelectCnt = -1;
        ReceiveSelectCnt = -1;

        for(auto it=PaintData.begin();it!=PaintData.end();++it)
            if(it.value().IsSelect)
                it.value().IsSelect = false;
        if(mt == PW::ModelType::PLOYGON)
        {

            int sc = 0;
            for(auto it=PaintData.begin();it!=PaintData.end();++sc,++it)
            {
                if(IsSelectPolygon(MouseLeftPressedPoint,it.value()))
                {
                    SelectCnt = sc;
                    ReceiveSelectCnt = SelectCnt;
                    it.value().IsSelect = true;
                    update();
                    return;
                }
            }
        }
        update();
    }
}

void PaintWidget::mouseReleaseEvent(QMouseEvent *rEvent)
{
    if(rEvent->button() == Qt::LeftButton)
    {
        MouseLeftIsPressed = false;
        QPoint curPoint = rEvent->pos();
        if(curPoint != MouseLeftPressedPoint)
            ++PaintStep;
        TmpPoints.clear();
        SelectCnt = -1;
    }
}

void PaintWidget::mouseMoveEvent(QMouseEvent *mEvent)
{
    if(MouseLeftIsPressed)
    {
        QPoint curPoint = mEvent->pos();
        TmpPoints.append(curPoint);

        if(SelectCnt == -1)
        {
            PW::PROPERTYDATA pd;
            pd.pen = pen;
            if(mt == PW::ModelType::ERASER)
                pd.pen.setColor(BackgroundColor);
            pd.Mt = mt;
            pd.Pt = pt;
            pd.BeginEndPoint = QPair<QPoint,QPoint>(MouseLeftPressedPoint,curPoint);
            pd.PaintData = TmpPoints;
            PaintData[PaintStep] = pd;
        }
        else
        {
            PW::PROPERTYDATA *pd = &PaintData[SelectCnt];
            QPoint tPoint = curPoint;
            tPoint -= MouseLeftPressedPoint;
            pd->BeginEndPoint.first  += tPoint;
            pd->BeginEndPoint.second += tPoint;
            MouseLeftPressedPoint = curPoint;
            pd = nullptr;
        }

        update();
    }
}

void PaintWidget::paintEllipose(QPainter *painter, PW::PROPERTYDATA *sp)
{
    QPair<QPoint,QPoint> BeginEndPoint = sp->BeginEndPoint;

    if(painter && sp->IsShow)
    {
        QPair<QPoint, QPoint> points = BeginEndPoint;
        painter->drawEllipse(QRect(points.first,points.second));

        QVector<QPoint> border;
        int startX = points.first.x();
        int startY = points.first.y();
        int endX   = points.second.x();
        int endY   = points.second.y();
        int offset = painter->pen().width() + 6;

        if(startX<endX && startY<endY)
        {
            int side1Len = endY - startY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(startX-offset,startY+cnt));

            int side2Len = endX - startX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(startX+cnt,endY+offset));

            int side3Len = endY - startY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(endX+offset,endY-cnt));

            int side4Len = endX - startX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(endX-cnt,startY-offset));
        }

        else if(startX>endX && startY<endY)
        {
            int side1Len = endY - startY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(endX-offset,startY+cnt));

            int side2Len = startX - endX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(endX+cnt,endY+offset));

            int side3Len = endY - startY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(startX+offset,endY-cnt));

            int side4Len = startX - endX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(startX-cnt,startY-offset));
        }

        else if(startX<endX && startY>endY)
        {
            int side1Len = startY - endY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(startX-offset,endY+cnt));

            int side2Len = endX - startX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(startX+cnt,startY+offset));

            int side3Len = startY - endY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(endX+offset,startY-cnt));

            int side4Len = endX - startX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(endX-cnt,endY-offset));
        }

        else if(startX>endX && startY>endY)
        {

            int side1Len = startY - endY;
            for(int cnt = 1;cnt <= side1Len;++cnt)
                border.append(QPoint(endX-offset,endY+cnt));

            int side2Len = startX - endX;
            for(int cnt = 1;cnt <= side2Len;++cnt)
                border.append(QPoint(endX+cnt,startY+offset));

            int side3Len = startY - endY;
            for(int cnt = 1;cnt <= side3Len;++cnt)
                border.append(QPoint(startX+offset,startY-cnt));

            int side4Len = startX - endX;
            for(int cnt = 1;cnt <= side4Len;++cnt)
                border.append(QPoint(startX-cnt,endY-offset));
        }


        if(sp->IsSelect)
        {
            painter->save();
            QPen pen(Qt::gray,2);
//            pen.setStyle(Qt::DotLine);
            painter->setPen(pen);
            painter->drawLines(border);
            painter->restore();

            selectPropertyWidget->setProperty(BeginEndPoint,ReceiveSelectCnt);
        }
    }
    painter = nullptr;
    sp = nullptr;
}
